/******************************************************************************
* 文件名称: uds_tp.h
* 内容摘要: UDS 诊断网络/传输层
* 创建者の: 孔佳伟
* 个人主页: https://gitee.com/thin-wind/jump
* 修改记录: 
******************************************************************************/

#include "uds_tp.h"
#include "id_reg.h"
#include "msg_buf.h"
#include "msg_log.h"
#include <string.h>


#define TP_MAX_LEN          4095                // 多帧数据总长度至多 4095 个字节

#define FRAME_TYPE(val)     ((val) >> 4)        // 获取帧类型
#define FRAME_NUM(val)      ((val) & 0x0F)      // 获取帧序号
#define FRAME_NUM_INC(val)  ((val) = ((val)++ >= 0x0F) ? 0 : (val))  // 帧序号自增


#define N_As_TIMEOUT        1000                // N_As 超时: 发送方没有及时发出首帧或者连续帧
#define N_Ar_TIMEOUT        1000                // N_Ar 超时: 接收方没有及时回复流控帧
#define N_Bs_TIMEOUT        1000                // N_Bs 超时: 发送方没有及时接收到接收方发出的流控帧            
#define N_Br_TIMEOUT        1000                // N_Br 超时: 接收方没有及时发出流控帧     
#define N_Cs_TIMEOUT        1000                // N_Cs 超时: 发送方没有及时发送连续帧
#define N_Cr_TIMEOUT        1000                // N_Cr 超时: 接收方没有及时收到连续帧 

static uint32_t N_As_cnt = 0;
static uint32_t N_Ar_cnt = 0;
static uint32_t N_Bs_cnt = 0;
static uint32_t N_Br_cnt = 0;
static uint32_t N_Cs_cnt = 0;
static uint32_t N_Cr_cnt = 0;


// N_PCI - Protocol Control Information, 协议控制信息
typedef enum N_PCI
{
    N_PCI_SF = 0x0,                             // 单帧
    N_PCI_FF = 0x1,                             // 首帧
    N_PCI_CF = 0x2,                             // 连续帧
    N_PCI_FC = 0x3,                             // 流控帧
} N_PCI;

// 流状态
typedef enum FS_E
{
    FS_CTS,                                     // 允许继续发送
    FS_WT,                                      // 等待
    FS_OVFLW,                                   // 溢出
    FS_INVALID,                                 // 非法值
} FS_E;

// 流控
typedef struct FC_S
{
    FS_E        flowState;                      // 流状态
    uint8_t     blockSize;                      // 块大小
    uint8_t     st;                             // 最小间隔时间
} FC_S;

static FC_S fc = {0};                           //  用于控制向外发送多帧数据

static uint8_t STmin = DEFAULT_ST;              // 用于通知发送方多帧发送的默认最小时间间隔，单位：ms

static uint8_t*         localRxBuf = NULL;
static uint16_t         localRxLen = 0;
static pRxcomplFunc     localRxComplCallback = NULL;
static uint16_t         OnePacketTotalLen = 0;
static uint16_t         localRxIdx = 0;

static uint8_t          frameInx = 0x1;

static uint8_t          startContinuousSend = 0;
static uint8_t*         localTxBuf = NULL;
static uint16_t         localTxLen = 0;
static pTxcomplFunc     localTxComplCallback = NULL;
static uint8_t          localTxIdx = 0;

static void TimeoutErrorHandle(void)
{



}

int UdsTpSend(uint8_t* txbuf, uint16_t txlen, pTxcomplFunc txComplCallback)
{
    Msg_S msg = {0};
    uint32_t i = 0;

    // 检查参数合法性
    if((NULL == txbuf) || (txlen > TP_MAX_LEN))
        return -1;

    if(txlen <= (FRAME_SIZE - 1))   // 单帧
    {
        msg.id = SEND_TO_ID;
        msg.data[0] = (0x0 << 4) | txlen;
        for(i = 0; i < txlen; i++)
            msg.data[i+1] = txbuf[i];
        memset(&msg.data[i + 1], PADDING_BYTE, FRAME_SIZE - i - 1);      // 无效位填充
        if(0 != PutToTxBuf(&msg))
        {
            MSG_LOG("Msg txbuf full\n");
            return -1;
        }
    }

    // startContinuousSend = 1;
    // localTxBuf = txbuf;
    // localTxLen = txlen;
    // localTxComplCallback = txComplCallback;
    
    return 0;
}

void UdsTp1msTask(void)
{
    


}

// 设置通知发送方连续帧发送的最小时间间隔，单位：ms
void SetSeparationTime(uint8_t st)
{
    STmin = st;
}

// 获取通知发送方连续帧发送的最小时间间隔，单位：ms
uint8_t GetSeparationTime(void)
{
    return STmin;
}


int UdsTpRecvReg(uint8_t* rxbuf, uint16_t rxlen, pRxcomplFunc rxComplCallback)
{
    // 检查参数合法性
    if((NULL == rxbuf) || (rxlen < FRAME_SIZE))
        return -1;

    localRxBuf = rxbuf;
    localRxLen = rxlen;
    localRxComplCallback = rxComplCallback;

    return 0;
}

// 处理单帧
static int HandleSingleFrame(uint8_t* buf, uint8_t len)
{
    uint8_t dataLen = 0;

    // 检查参数合法性
    if(NULL == buf)
        return -1;

    // 单帧时数据长度为第一个字节的低 4bit 
    dataLen = (buf[0] & 0x0F);

    if(NULL == localRxBuf)
        return -1;

    // 单帧有效数据长度最大 FRAME_SIZE - 1
    if(dataLen > FRAME_SIZE - 1)
    {
        MSG_LOG("Single frame data length exceed\n");
        return -1;
    }

    // 拷贝有效数据到上层定义的数据缓冲区
    memcpy(localRxBuf, &buf[1], dataLen);

    // 通知上层，接收完成
    if(NULL != localRxComplCallback)
        localRxComplCallback(localRxBuf, dataLen);

    return 0;
}

// 返回流控帧
static int ReturnFlowControlFrame(FS_E fs, uint8_t bs, uint8_t st)
{
    Msg_S msg = {0};
    msg.id = SEND_TO_ID;
    msg.data[0] = (0x3 << 4) | fs;              // 流控 | 允许发送
    msg.data[1] = bs;                           // BS = 0, 之后再无流控帧，可无限制发送
    msg.data[2] = st;                           // 多帧发送的最小时间间隔
    memset(&msg.data[3], PADDING_BYTE, FRAME_SIZE - 3);      // 无效位填充
    PutToTxBuf(&msg);
}

// 处理首帧
static int HandleFirstFrame(uint8_t* buf, uint8_t len)
{
    uint16_t dataLen = 0;

    // 检查参数合法性
    if(NULL == buf)
        return -1;

    // 多帧的第一帧即为首帧，其第一个字节的低 4bit 和 第二字节组成 12bit 的数据长度
    OnePacketTotalLen = ((buf[0] & 0x0F) << 8) + buf[1];

    // 12bit 数据长度最大 4095，所以这里不需要做数据长度超限处理

    // 返回流控帧，允许继续无限制发送，最小间隔时间：STmin (ms)
    ReturnFlowControlFrame(FS_CTS, 0, STmin);

    // 首帧时将数据接收下标和连续帧的帧序号复位
    localRxIdx = 0;
    frameInx = 1;

    // 首帧可携带多帧报文的前 FRAME_SIZE - 2 个字节数据
    // 拷贝有效数据到上层定义的数据缓冲区，同时数据接收下标 + (FRAME_SIZE - 2)
    memcpy(localRxBuf + localRxIdx, &buf[2], FRAME_SIZE - 2);
    localRxIdx += (FRAME_SIZE - 2);
    
    return 0;
}

// 处理连续帧
static int HandleConsecutiveFrame(uint8_t* buf, uint8_t len)
{
    uint8_t lastBytes = 0;

    // 检查参数合法性
    if(NULL == buf)
        return -1;

    // 帧序号检测
    if(frameInx == FRAME_NUM(buf[0]))
    {
        FRAME_NUM_INC(frameInx);
    }
    else
    {
        MSG_LOG("Frame num error\n");
        return -1;
    }

    if((localRxIdx + (FRAME_SIZE - 1)) >= OnePacketTotalLen)    // 最后一帧数据
    {
        lastBytes = OnePacketTotalLen - localRxIdx;             // 最后一帧数据中的有效数据长度
        // 拷贝有效数据到上层定义的数据缓冲区，同时数据接收下标 + (FRAME_SIZE - 1)
        memcpy(localRxBuf + localRxIdx, &buf[1], FRAME_SIZE - 1);
        localRxIdx += lastBytes;
        
        // 通知上层，接收完成
        if(NULL != localRxComplCallback)
            localRxComplCallback(localRxBuf, localRxIdx);
    }
    else                                                        // 非最后一帧数据
    {
        // 拷贝有效数据到上层定义的数据缓冲区，同时数据接收下标 + (FRAME_SIZE - 1)
        memcpy(localRxBuf + localRxIdx, &buf[1], FRAME_SIZE - 1);
        localRxIdx += (FRAME_SIZE - 1);
    }

    return 0;
}

// 处理流控帧
static int HandleFlowControlFrame(uint8_t* buf, uint8_t len)
{
    // 检查参数合法性
    if(NULL == buf)
        return -1;

    // 流状态为非法值
    if((buf[0] & 0x0F) >= FS_INVALID)
    {
        MSG_LOG("Flow State Invalid");
        return -1;
    }

    fc.flowState = (FS_E)(buf[0] & 0x0F);
    fc.blockSize = buf[1];
    fc.st = buf[2];
}

// 接收到一帧诊断报文
void RecvOneFrame(uint8_t* buf, uint8_t len)
{
    // 第一个字节的高 4 bit 表示帧类型
    uint8_t frameType = FRAME_TYPE(buf[0]);

    switch (frameType)
    {
        case N_PCI_SF:          // 单帧
            HandleSingleFrame(buf, len);
            break;

        case N_PCI_FF:          // 首帧
            HandleFirstFrame(buf, len);
            break;

        case N_PCI_CF:          // 连续帧
            HandleConsecutiveFrame(buf, len);
            break;

        case N_PCI_FC:          // 流控帧
            HandleFlowControlFrame(buf, len);
            break;
        
        default:
            MSG_LOG("Invalid frame type\n");
            break;
    }
}

ID_REG(GET_FROM_ID, RecvOneFrame);
